#pragma ocne
#include "google/protobuf/service.h"
#include "google/protobuf/descriptor.h"
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/TcpConnection.h>
#include <string>
#include <unordered_map>
/*
框架提供的专门发布rpc服务的网络对象类
*/
class RpcProvider
{
    // service服务类型消息
    struct ServiceInfo
    {
        // 服务对象
        google::protobuf::Service* m_service;
        // hash服务方法
        std::unordered_map<std::string, const google::protobuf::MethodDescriptor*> m_methodMap;
    };
private:
    // 组合EventLoop
    muduo::net::EventLoop m_eventLoop;
    // 存储注册成功的服务对象和其服务方法的所有信息
    std::unordered_map<std::string, ServiceInfo> m_serviceMap;

public:
    /*
    所以在设计上,参数一定要抽象化,而不是说为了给UserSerivce服务
    参数就设计为UserService*对象,这样子就不是框架了
    查看protobuf生成的.h文件，可以发现所有的message生成的类都继承了Service类
    UserService : public fixbug::UserServiceRpc
    UserServiceRpc : public google::protobuf::Service service
    因此,我们可以将参数设置为Service*
    */
    // 这里是框架提供给外部使用的,可以发布rpc方法的函数接口
    void NotifyService(google::protobuf::Service* service);
    // 启动rpc服务节点,开始提供rpc远程网络调用服务
    void Run();
private:
    // 新的socket连接回调函数
    void OnConnection(const muduo::net::TcpConnectionPtr&);
    /*
    在框架内部,RpcProvider和RpcConsumer协商好通信用的protobuf数据类型(即协议)
    关注的对象:service_name method_name args  定义proto的message类型,进行数据头的序列化和反序列化
    message: service_name method_name args_size
    数据格式: header_size(4字节) + header_str + args_str, eg: 16UserServiceLoginwangzn123456
    header_size以二进制方式描述header_str的数据大小
    */
    // 已建立连接的用户的读写事件回调函数
    void OnMessage(const muduo::net::TcpConnectionPtr&, muduo::net::Buffer*, muduo::Timestamp);
    // Closure的回调操作,用于序列化rpc的响应和网络发送
    void SendRpcResponse(const muduo::net::TcpConnectionPtr&, google::protobuf::Message*);
};